<?php
class Cache {
    private static $cache = null;
    private static $cacheEngine = 'file';
    private static $locks = array();
    private function __construct(){}
    
    #获取缓存实例
    private static function getCache() {
        if (null === self::$cache) {
            $cacheEngine = strtolower(Config::get('CACHE_ENGINE'));
            self::$cacheEngine = $cacheEngine;
            if ('file' == $cacheEngine) {
                self::$cache = true;
            } else {
                $cacheClass = ucfirst($cacheEngine) . 'Cache';
                $classFile = PUMP_CORE . '/CacheDriver/' . $cacheClass . '.class.php';
                if (file_exists($classFile)){
                    require_once($classFile);
                    self::$cache = new $cacheClass();
                    $appKey = Application::getKey();
                } else {
                    throw new Exception('找不到缓存驱动"' . $cacheClass . '"');
                }
                
            }
        }
        return self::$cache;
    }
    
    #永久缓存， 使用文件缓存
    public static function eternal($nameSpace, $key, $val=null) {
        return self::fileCache($nameSpace, $key, $val,0);
    }
    
    public static function delEternal($nameSpace, $key='') {
        self::delete($nameSpace, $key, 'file');
    }
    
    #文件缓存
    private static function fileCache($nameSpace, $key, $val=null, $expire=0) {
        $cacheFile = DATA_DIR . '/' . $nameSpace . '/' . $key . '.php';
        if (null === $val) {
             if (file_exists($cacheFile)) {
                $cacheContents = file_get_contents($cacheFile);
                $value = self::readFromCache($cacheContents);
                if (null == $value) @unlink($cacheFile);
                return $value;
             }
             return null;
        } else {
            $cacheDir = dirname($cacheFile);
            if (false == is_dir($cacheDir)) {
                if (false == @mkdir($cacheDir, 0777, true)){
                    throw new Exception('缓存目录"' . $cacheDir . '"无法创建,请设置目录"' . DATA_DIR . '为可写"');
                }
            }
            $cacheContents = self::getCacheContents($val, $expire);
            if($cacheContents) file_put_contents($cacheFile, $cacheContents);
        }
    }
    #根据名称空间及键值生成系统唯一的缓存键值
    private static function getCacheKey($nameSpace, $key) {
        $appKey = Application::getKey();
        return md5($appKey . '^' . $nameSpace . '^' . $key);
    }
    
    #设置缓存变量
    public static function set($nameSpace, $key, $val, $expire=0) {
        $cache = self::getCache();
        if ('file' == self::$cacheEngine) 
            return self::fileCache($nameSpace, $key, $val, $expire);
        
        $cacheKey = self::getCacheKey($nameSpace, $key);
        if('db' != self::$cacheEngine) {
            if ($cache->set($cacheKey, $val, $expire)) {
                self::setHash($nameSpace, $cacheKey);
            }
        } else {
            $appKey = Application::getKey();
            $dbNameSpace = md5($appKey . '_' . $nameSpace);
            $cache->set($dbNameSpace, $cacheKey, $val, $expire);
        }
    }
    
    #获取缓存变量
    public static function get($nameSpace, $key) {
        $cache = self::getCache();
        if ('file' == self::$cacheEngine) 
            return self::fileCache($nameSpace, $key);
            
        $cacheKey = self::getCacheKey($nameSpace, $key);
        if('db' != self::$cacheEngine) {
            self::setHash($nameSpace, $cacheKey);
        }
        return $cache->get($cacheKey);
    }
    
    #删除缓存变量， 当没有设置键值时删除名称空间内所有缓存值
    public static function delete($nameSpace, $key=null, $engine='') {
        if(false == $engine)$cache = self::getCache();
        $engine = $engine ? $engine : self::$cacheEngine;
        if ('file' == $engine) {
            if (null != $key) {  
                $cacheFile = DATA_DIR . '/' . $nameSpace . '/' . $key . '.php';
                @unlink($cacheFile);
            } else {
                if (function_exists('exec')) {
                    if (DIRECTORY_SEPARATOR == '/') {
                        @exec('rm -rf ' . DATA_DIR . '/' . $nameSpace . '/*.php');
                    } else {
                        $command = str_replace('/', '\\', 'del  ' . DATA_DIR . '\\' . $nameSpace . '\\*.php');
                        @exec($command);
                    }
                    
                } else {
                    $fileList = glob(DATA_DIR . '/' . $nameSpace . '/*.php');
                    foreach ($fileList as $fileName) {
                        @unlink($fileName);
                    }
                }
            }
        } else {
            if (null != $key) {
                $cacheKey = self::getCacheKey($nameSpace, $key);
                $cache->delete($cacheKey);
                if('db' != $engine)
                    self::deleteHash($nameSpace, $cacheKey);
            } else {
                if('db' != $engine) {
                    $cacheHash = self::getHash();
                    if ($cache->delete($cacheHash[md5($nameSpace)]))
                        unset($cacheHash[$nameSpace]);
                    $appKey = Application::getKey();
                    $cache->set($appKey, $cacheHash);
                } else {
                    $appKey = Application::getKey();
                    $dbNameSpace = md5($appKey . '_' . $nameSpace);
                    $cache->deleteNameSpace($dbNameSpace);
                }
            }
        }
    }
    
    #获取名称空间关联的所有已存储键值
    private static function getHash() {
        $cache = self::getCache();
        $appKey = Application::getKey();
        $cacheHash = $cache->get($appKey);
        return $cacheHash;
    }
    
    #新增缓存键值
    private static function setHash($nameSpace, $cacheKey) {
        $appKey = Application::getKey();
        $cache = self::getCache();
        $cacheHash = self::getHash();
        $cacheHash[md5($nameSpace)][$cacheKey] = true;
        $cache->set($appKey, $cacheHash);
    }
    
    #删除缓存键值
    private static function deleteHash($nameSpace, $cacheKey) {
        $appKey = Application::getKey();
        $cache = self::getCache();
        $cacheHash = self::getHash();
        unset($cacheHash[md5($nameSpace)][$cacheKey]);
    }
    
    #文件缓存时根据变量及过期时间生成缓存内容
    private static function getCacheContents($value, $expire=0) {
        if ($expire != 0)
            $expire = $expire >= time() ? $expire : $expire + time();
        $contents = "<?php exit(); ?>";
        $contents .= sprintf('%010d', $expire) . serialize($value);
        return $contents;
    }
    
    #解析缓存内容并返回
    private static function readFromCache($cacheContents) {
        $contents = trim($cacheContents, "<?php exit(); ?>");
        $expire = abs(substr($contents, 0, 10));
        if ($expire >0 && $expire < time()) {
            return null;
        }
        return unserialize(substr($contents, 10));
    }
    
    #关闭缓存连接
    public static function close() {
        $cache = self::getCache();
        if('file' != self::$cacheEngine) {
            $cache->close();
        }
    }

    public static function dumpAllCache() {
        $cache = self::getCache();
        if('file' == self::$cacheEngine) {
            die('当前缓存驱动为文件型，不提供支持');
        }
        $hash = self::getHash();
        $cacheArray = array();
        if(is_array($hash)) 
        foreach($hash as $nameSpace=>$keys) {
            foreach($keys as $key=>$keyset)
                $cacheArray[$key] = $cache->get($key);
        }
        echo '<pre>';
        print_r($cacheArray);
        echo '</pre>';
    }

    public static function clearAllCache() {
        $cache = self::getCache();
        if('file' == self::$cacheEngine) {
            die('当前缓存驱动为文件型，请手工清除缓存目录');
        }
        $hash = self::getHash();
        if(is_array($hash))
        foreach($hash as $nameSpace=>$keys) {
            foreach($keys as $key=>$keyset)
                $cacheArray[$key] = $cache->delete($key);
        }
    }
};
?>